#include "client.h"
#include "list.h"

Client::Client(char *DEVICE)
{
    this->fc = new FlowControl(DEVICE);
    this->buffer = new List();
}

void Client::controlClient()
{
    cout << "Cliente" << endl;
    cout << "..." << endl;
    string path = "";
    bool getOut = false;

    while ( !getOut){
        getline(cin, path);

        if (path.c_str()[0] == 'l' && path.length() >= 1){
            if (path.length() > 1 && path.c_str()[1] != ' '){
                cout << "Error: Use l path ou somente l" << endl;
            } else {
                if (path.length() > 1 && path.c_str()[1] == ' ')
                    this->lCmd((char *)&(path.c_str()[2]));
                if (path.length() == 1)
                    this->lCmd(NULL);
            }
        } else if (path.c_str()[0] == 'c'){
            if (path.length() < 3 || path.c_str()[1] != ' ')
                cout << "Error: Use c path" << endl;
            else
                this->cCmd((char *)&(path.c_str()[2]));
        } else if (path.c_str()[0] == 'f'){
            if (path.length() < 3 || path.c_str()[1] != ' ')
                cout << "Error: Use f path" << endl;
            else
                this->fCmd((char *)&(path.c_str()[2]));
        } else if (path.c_str()[0] == 'a'){
            if (path.length() < 3 || path.c_str()[1] != ' ')
                cout << "Error: Use a file" << endl;
            else
                this->aCmd((char *)&(path.c_str()[2]));
        } else if (path.c_str()[0] == 'e'){
            if (path.length() < 3 || path.c_str()[1] != ' ')
                cout << "Error: Use e file" << endl;
            else
                this->eCmd((char *)&(path.c_str()[2]));
        } else if (path == "quit" || cin.eof()){
            this->qCmd();
            getOut = !getOut;
        } else
            cout << "Cmd not found" << endl;

        path.clear();
        cin.clear();
    }

    cout << "Finalizado." << endl;
}

void Client::lCmd(char *path)
{
    message *data = new message(), *received = new message();
    unsigned short seq = 0;

    if (path){
        if  (this->fc->sendUntilZ((byte *)path, strlen(path)+1, (byte)'l', (byte)'Y')){
            if (this->fc->receiveUntilZ(this->buffer, 'X', 0))
                if (this->buffer->getSize() > 0)
                    this->buffer->showList(false);
                else
                  cout << "Erro, verifique as pemissões e se realmente o arquivo/diretório existe" << endl;
            else
                cout << "Erro, não recebi o resultado completo da solicitação 'l'" << endl;
        } else
            cout << "Erro, não consegui enviar solicitação 'l'." << endl;
    } else {
        data->setMessage(seq, 'l', NULL, 0);
        
        if (this->fc->send(data, received, 'X', true, true)){
            this->buffer->copy(received->getData(), received->getSize()-2);
            seq++;

            if (this->fc->receiveUntilZ(this->buffer, 'X', 1))
                this->buffer->showList(false);
            else
                cout << "Erro, não recebi o resultado completo da solicitação 'l'" << endl;
        } else
            cout << "Erro, não consegui enviar solicitação 'l'." << endl;
    }
    
    delete data;
    delete received;
    this->buffer->clear();
}

void Client::cCmd(char *path)
{
    message *msg = new message();
    
    if  (this->fc->sendUntilZ((byte *)path, strlen(path)+1, (byte)'c', (byte)'Y')){
        if (this->fc->receive(msg, 'V', false)){
            if (msg->getType() == 'E'){
                switch (msg->getData()[0]){
                    case S_ERROR_DENY_R:
                        cout << "Você não tem permissão para acessar " << path << endl;
                        break;
                    case S_ERROR_UNKN:
                        cout << path << " não é uma pasta" << endl;
                        break;
                    case S_ERROR_DIR_N_EXIT:
                        cout << "Diretório inexistente" << endl;
                        break;
                }
            } else
                cout << "Você está em " << path << endl;
        } else
               cout << "Erro, não obtive resposta da solicitação 'c'." << endl;
    } else
        cout << "Erro, não consegui enviar solicitação 'c'." << endl;

    delete msg;
    this->buffer->clear();
}

void Client::fCmd(char *nameFile)
{
    message *msg = new message();

    if (this->fc->sendUntilZ((byte *)nameFile, strlen(nameFile)+1, (byte)'f', (byte)'Y')){
        if (this->fc->receive(msg, 'V', false)){
            this->buffer->clear();

            if (msg->getType() == 'Y'){
                if ( !this->fc->receiveUntilZ(this->buffer, 'X', 0))
                    cout << "Erro, não recebi o resultado completo da solicitação 'f'" << endl;
                else
                    this->buffer->showList();
            } else {
                switch (msg->getData()[0]){
                    case S_ERROR_N_EXIST:
                        cout << "Arquivo \"" << nameFile << "\" inexistente" << endl;
                        break;
                    case S_ERROR_DENY_R:
                        cout << "Arquivo \"" << nameFile << "\" sem permissão para leitura" << endl;
                        break;
                    case S_EOF:
                        cout << "Arquivo \"" << nameFile << "\" vazio" << endl;
                        break;
                    case S_ERROR_UNKN:
                        cout << "Algum erro desconhecido aconteceu." << endl;
                        cout << "Obs: você deve estar fazendo alguma operação não permitida.";
                        cout << endl;
                        break;
                }
            }
        } else
            cout << "Erro, não obtive resposta da solicitação 'f'" << endl;
    } else
        cout << "Erro, não consegui enviar solicitação 'f'" << endl;

    this->buffer->clear();
    delete msg;
}

void Client::aCmd(char *nameFile)
{
    message *msg = new message();
    string data = "";

    if (this->fc->sendUntilZ((byte *)nameFile, strlen(nameFile)+1, (byte)'a', (byte)'Y')){
        if (this->fc->receive(msg, 'V', false)){
            if (msg->getType() == 'Y'){
                cout << "d >>> ";
		getline(cin, data);
                data.append("\n");
		cin.clear();

                if ( !this->fc->sendUntilZ((byte *)data.c_str(), data.length(), (byte)'D', (byte)'Y'))
                    cout << "Erro, não consegui enviar por completo o append" << endl;
            } else {
                switch (msg->getData()[0]){
                    case S_ERROR_N_EXIST:
                        cout << "Arquivo \"" << nameFile << "\" inexistente" << endl;
                        break;
                    case S_ERROR_DENY_R:
                        cout << "Arquivo \"" << nameFile << "\" sem permissão de escrita" << endl;
                        break;
                    case S_EOF:
                        cout << "Arquivo \"" << nameFile << "\" vazio" << endl;
                        break;
                    case S_ERROR_UNKN:
                        cout << "Algum erro desconhecido aconteceu." << endl;
                        cout << "Obs: você deve estar fazendo alguma operação não permitida";
                        cout << endl;
                        break;
                }
            }
        } else
            cout << "Erro, não obtive resposta da solicitação 'a'" << endl;
    } else
        cout << "Erro, não consegui enviar solicitação 'a'" << endl;

    this->buffer->clear();
    delete msg;
}

void Client::eCmd(char *nameFile)
{
    message *msg = new message();
    string data = "";
    string line = "0";
    bool error = false;

    if (this->fc->sendUntilZ((byte *)nameFile, strlen(nameFile)+1, (byte)'e', (byte)'Y')){
        if (this->fc->receive(msg, 'V', false)){
            if (msg->getType() == 'Y'){
                cout << "Digite a Linha:" << endl;
                getline(cin, line);
		cin.clear();

                if (this->fc->sendUntilZ((byte *)line.c_str(), line.length()+1, (byte)'g', (byte)'Y')){
                    if (this->fc->receive(msg, 'V', false)){
                        if(msg->getType() == 'Y'){
                            cout << "Digite os dados: \n>>>" << endl;
                            getline(cin, data);

                            if ( !this->fc->sendUntilZ((byte *)data.c_str(), data.length(), (byte)'D', (byte)'Y'))
                                cout << "Erro, não consegui enviar solicitação 'd'" << endl;
                            cin.clear();
                        } else
                            error = true;
                    } else
                        cout << "Erro, não obtive resposta da solicitação 'g'" << endl;
                } else
                    cout << "Erro, não consegui enviar solicitação 'g'" << endl;
            } else
                error = true;
        } else
            cout << "Erro, não obtive resposta da solicitação 'e'" << endl;
    } else
        cout << "Erro, não consegui enviar solicitação 'e'" << endl;

    if(error){
        switch (msg->getData()[0]){
            case S_ERROR_N_EXIST:
                cout << "Arquivo \"" << nameFile << "\" inexistente" << endl;
                break;
            case S_ERROR_DENY_R:
                cout << "Arquivo \"" << nameFile << "\" sem permissão para leitura" << endl;
                break;
            case S_EOF:
                cout << "Arquivo \"" << nameFile << "\" vazio" << endl;
                break;
            case S_ERROR_UNKN:
                cout << "Algum erro desconhecido aconteceu." << endl;
                cout << "Obs: Verifique se você está tentando alterar uma linha dentro do limite do arquivo.";
                cout << endl;
                break;
        }
    }
    
    this->buffer->clear();
    delete msg;
}

/*******************************************************************************/
void Client::qCmd()
{
    message *msg = new message();

    msg->setMessage(0, 'q', NULL, 0);
    this->fc->send(msg, NULL, 'q');

    delete msg;
}


